﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace _3D_FileExplorer
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Camera : Microsoft.Xna.Framework.GameComponent
    {
        public Vector3 cameraPosition { get; set; }
        public Matrix view { get;  set; }
        public Matrix projection { get; set; }
        public Vector3 cameraDirection;
        public Vector3 cameraUp;
        float speed = Fe.par.cameraSpeed;
        public bool runCamera = true;
        MouseState prevMouseState;
 

        public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up)
            : base(game)
        {
            cameraPosition = pos;
            cameraDirection = target - pos;
            cameraDirection.Normalize();
            cameraUp = up;
            projection = Matrix.CreatePerspectiveFieldOfView(
            MathHelper.PiOver4,
            (float)Fe.canvas.Width /
            (float)Fe.canvas.Height, 1, 100000);
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here
            // Set mouse position and do initial get state
            Mouse.SetPosition(Game.Window.ClientBounds.Width / 2,
            Game.Window.ClientBounds.Height / 2);
            prevMouseState = Mouse.GetState( );


            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            int vdrift = 0;
            int hdrift = 0;
            // TODO: Add your update code here
            if ((Fe.canvas.Focused && !Fe.menuIsActive)&&(runCamera)&&!Fe.par.keyBoardControl)
            {
                if (Fe.par.keyBoardControl == false)
                {
                    // Move forward/backward
                    if (Keyboard.GetState().IsKeyDown(Keys.W))
                        cameraPosition += cameraDirection * speed;
                    if (Keyboard.GetState().IsKeyDown(Keys.S))
                        cameraPosition -= cameraDirection * speed;

                    // Move side to side
                    if (Keyboard.GetState().IsKeyDown(Keys.A))
                        cameraPosition += Vector3.Cross(cameraUp, cameraDirection) * speed;
                    if (Keyboard.GetState().IsKeyDown(Keys.D))
                        cameraPosition -= Vector3.Cross(cameraUp, cameraDirection) * speed;
                }

                #region CAMERA CALCULATIONS
                // Rotation parameters
                if (Mouse.GetState().MiddleButton != ButtonState.Pressed)
                {
                    if ((Mouse.GetState().Y < 10)&&(Mouse.GetState().Y > -70))
                    {
                        vdrift = -2;
                    }
                    else if (((Mouse.GetState().Y - Fe.canvas.Height) > -30)&&((Mouse.GetState().Y - Fe.canvas.Height) < 40))
                    {
                        vdrift = 2;
                    }
                    else
                    {
                        vdrift = 0;
                    }

                    if ((Mouse.GetState().X < 50)&&(Mouse.GetState().X > -30))
                    {
                        hdrift = -2;
                    }
                    else if (((Mouse.GetState().X - Fe.canvas.Width) > -50)&&((Mouse.GetState().X - Fe.canvas.Width) < 30))
                    {
                        hdrift = 2;
                    }
                    else
                    {
                        hdrift = 0;
                    }
                }
                else
                {
                    vdrift = (Mouse.GetState().Y - prevMouseState.Y);
                    hdrift = (Mouse.GetState().X - prevMouseState.X);
                }
                #endregion



                // Pitch rotation
                cameraDirection = Vector3.Transform(cameraDirection,
                Matrix.CreateFromAxisAngle(Vector3.Cross(cameraUp, cameraDirection), (MathHelper.PiOver4 / 100) * vdrift));
                cameraUp = Vector3.Transform(cameraUp,
                Matrix.CreateFromAxisAngle(Vector3.Cross(cameraUp, cameraDirection), (MathHelper.PiOver4 / 100) * vdrift));

                // Yaw rotation
                cameraDirection = Vector3.Transform(cameraDirection, Matrix.CreateFromAxisAngle(cameraUp, (-MathHelper.PiOver4 / 150) * hdrift));
                // Reset prevMouseState
                prevMouseState = Mouse.GetState();
            }
            // Recreate the camera view matrix
            CreateLookAt();
            base.Update(gameTime);
        }
        private void CreateLookAt()
        {
            view = Matrix.CreateLookAt(cameraPosition, cameraPosition + cameraDirection, cameraUp);
        }
        public void EnableCameraMovement(bool status)
        {
            runCamera = status;
        }

        public void SetCameraPosition(Vector3 pos, Vector3 target, Vector3 up)
        {
            cameraPosition = pos;
            cameraDirection = target - pos;
            cameraDirection.Normalize();
            cameraUp = up;
        }
    }
}